home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / vm / vmMigrate.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-19  |  19.5 KB  |  750 lines

  1. /*
  2.  * vmMigrate.c --
  3.  *
  4.  *    Routines to handle process migration from the standpoint of virtual
  5.  *    memory.
  6.  *
  7.  * Copyright 1986 Regents of the University of California
  8.  * All rights reserved.
  9.  */
  10.  
  11. #ifndef lint
  12. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/vm/vmMigrate.c,v 9.12 91/11/04 21:16:35 jhh Exp $ SPRITE (Berkeley)";
  13. #endif not lint
  14.  
  15. #include <sprite.h>
  16. #include <vm.h>
  17. #include <vmInt.h>
  18. #include <lock.h>
  19. #include <proc.h>
  20. #include <procMigrate.h>
  21. #include <fs.h>
  22. #include <fsio.h>
  23. #include <stdlib.h>
  24. #include <byte.h>
  25. #include <stdio.h>
  26. #include <bstring.h>
  27. #include <assert.h>    
  28.  
  29. static ReturnStatus EncapSegment _ARGS_((Vm_Segment *segPtr,
  30.     Proc_ControlBlock *procPtr, Address *bufPtrPtr));
  31. ENTRY static void PrepareSegment _ARGS_((Vm_Segment *segPtr));
  32. static ReturnStatus FlushSegment _ARGS_((Vm_Segment *segPtr));
  33. static void FreePages _ARGS_((Vm_Segment *segPtr));
  34. ENTRY static void LoadSegment _ARGS_((int length, register Address buffer,
  35.     register Vm_Segment *segPtr));
  36. ENTRY static ReturnStatus CheckSharers _ARGS_((register Vm_Segment *segPtr,
  37.     Proc_EncapInfo *infoPtr));
  38.  
  39. /*
  40.  * Define the number of ints transferred... FIXME: change to a struct.
  41.  */
  42. #define NUM_FIELDS 5
  43.  
  44.  
  45.  
  46. /*
  47.  *----------------------------------------------------------------------
  48.  *
  49.  * Vm_InitiateMigration --
  50.  *
  51.  *    Set up a process for migration.  Lock the dirty pages of each
  52.  *    segment, and free the rest.  Flush the dirty pages to disk.
  53.  *
  54.  * Results:
  55.  *    SUCCESS is returned directly; the size of the encapsulated state
  56.  *    is returned in infoPtr->size.
  57.  *
  58.  * Side effects:
  59.  *    The pages in the process are flushed.  Any copy-on-write pages
  60.  *    are isolated.
  61.  *
  62.  *----------------------------------------------------------------------
  63.  */
  64.  
  65. /* ARGSUSED */
  66. ReturnStatus
  67. Vm_InitiateMigration(procPtr, hostID, infoPtr)
  68.     Proc_ControlBlock *procPtr;            /* process being migrated */
  69.     int hostID;                    /* host to which it migrates */
  70.     Proc_EncapInfo *infoPtr;            /* area w/ information about
  71.                          * encapsulated state */
  72. {
  73.     int            seg;
  74.     Vm_Segment         *segPtr;
  75.     Vm_Segment         **segPtrPtr;
  76.     int            fsSize;
  77.     int            size = 0;
  78.     ReturnStatus    status;
  79.     int            varSize;
  80.  
  81.  
  82.     segPtrPtr = procPtr->vmPtr->segPtrArray;
  83.     status = CheckSharers(segPtrPtr[VM_HEAP], infoPtr);
  84.     if (status != SUCCESS) {
  85.     return(status);
  86.     }
  87.     fsSize = Fs_GetEncapSize();
  88.  
  89.     /*
  90.      * Prepare each segment for migration.  This involves some work in
  91.      * a monitored procedure and an unmonitored one.
  92.      */
  93.     for (seg = VM_CODE; seg < VM_NUM_SEGMENTS; seg++) {
  94.     segPtr = segPtrPtr[seg];
  95.     if (segPtr->type != VM_CODE) {
  96.         if (vm_CanCOW) {
  97.         /*
  98.          * Get rid of all copy-on-write dependencies.
  99.          */
  100.         status = VmCOWCopySeg(segPtr);
  101.         if (status != SUCCESS) {
  102.             printf("Warning: Vm_MigrateSegment: Could not copy segment\n");
  103.             return(status);
  104.         }
  105.         }
  106.         PrepareSegment(segPtr);
  107.         /*
  108.          * Unlock the process while flushing it to the server -- we might
  109.          * have to wait a while while this is going on.
  110.          */
  111.         Proc_Unlock(procPtr);
  112.         status = FlushSegment(segPtr);
  113.         Proc_Lock(procPtr);
  114.         if (status != SUCCESS) {
  115.         return(status);
  116.         }
  117.         varSize = segPtr->ptSize * sizeof(Vm_PTE);
  118.     } else {
  119.         varSize = sizeof(Vm_ExecInfo);
  120.     }
  121.     size += NUM_FIELDS * sizeof(int) + varSize + fsSize;
  122.     }
  123.     infoPtr->size = size;
  124.     return(SUCCESS);
  125. }
  126.  
  127.  
  128. /*
  129.  *----------------------------------------------------------------------
  130.  *
  131.  * Vm_EncapState --
  132.  *
  133.  *    Encapsulate the state of a process's virtual memory.  All the
  134.  *    work in going through its page tables has been done, so
  135.  *    just wait for all its pages to be written to disk, then
  136.  *    package up the state.
  137.  *
  138.  * Results:
  139.  *    If any error occurs with writing the swap files, an error is
  140.  *    indicated; otherwise, SUCCESS is returned.
  141.  *
  142.  * Side effects:
  143.  *    Each of the process's segments is freed.
  144.  *
  145.  *----------------------------------------------------------------------
  146.  */
  147. /* ARGSUSED */
  148. ReturnStatus
  149. Vm_EncapState(procPtr, hostID, infoPtr, bufferPtr)
  150.     register Proc_ControlBlock     *procPtr;  /* The process being migrated */
  151.     int hostID;                   /* host to which it migrates */
  152.     Proc_EncapInfo *infoPtr;           /* area w/ information about
  153.                         * encapsulated state */
  154.     Address bufferPtr;               /* Pointer to allocated buffer */
  155. {
  156.     ReturnStatus status;
  157.     Vm_Segment         *segPtr;
  158.     Vm_Segment         **segPtrPtr;
  159.     int            seg;
  160.  
  161.  
  162.     /*
  163.      * Encapsulate the virtual memory, and set up the process so the kernel
  164.      * knows the process has no VM on this machine.
  165.      */
  166.     
  167.     procPtr->genFlags |= PROC_NO_VM;
  168.  
  169.     segPtrPtr = procPtr->vmPtr->segPtrArray;
  170.  
  171.     /*
  172.      * Encapsulate each segment.  If it's not a code segment, it must
  173.      * be freed up.
  174.      */
  175.     for (seg = VM_CODE; seg < VM_NUM_SEGMENTS; seg++) {
  176.     segPtr = segPtrPtr[seg];
  177.     if (segPtr->type != VM_CODE) {
  178.         FreePages(segPtr);
  179.         if (segPtr->flags & VM_SEG_IO_ERROR) {
  180.         return(VM_SWAP_ERROR);
  181.         }
  182.     }
  183.         status = EncapSegment(segPtr, procPtr, &bufferPtr);
  184.     if (status != SUCCESS) {
  185.         return(status);
  186.     }
  187.     }
  188.     return(SUCCESS);
  189. }
  190.  
  191.  
  192. /*
  193.  *----------------------------------------------------------------------
  194.  *
  195.  * Vm_DeencapState --
  196.  *
  197.  *    Deencapsulate the state of a process's virtual memory. 
  198.  *    For each segment, get the information from a foreign
  199.  *    Vm_Segment from a buffer and create a segment for it on this
  200.  *    (the remote) node.  Set up the file pointer for its swap file,
  201.  *    if it is a stack or heap segment.  If it is a code segment, do
  202.  *    a Vm_SegmentFind (just as Proc_Exec does) and initialize the
  203.  *    page tables if necessary, then return.
  204.  *
  205.  * Results:
  206.  *    If any error occurs with deencapsulating the swap files, an error is
  207.  *    indicated; otherwise, SUCCESS is returned.
  208.  *
  209.  * Side effects:
  210.  *    Creates segments for the process.
  211.  *
  212.  *----------------------------------------------------------------------
  213.  */
  214. /* ARGSUSED */
  215. ReturnStatus
  216. Vm_DeencapState(procPtr, infoPtr, buffer)
  217.     register Proc_ControlBlock     *procPtr;  /* The process being migrated */
  218.     Proc_EncapInfo *infoPtr;           /* area w/ information about
  219.                         * encapsulated state */
  220.     Address buffer;               /* Pointer to allocated buffer */
  221. {
  222.     ReturnStatus status;
  223.     Vm_Segment         *segPtr;
  224.     int            seg;
  225.     int     offset;
  226.     int     fileAddr;
  227.     int     type;
  228.     int     numPages;
  229.     int     varSize;
  230.     int     ptSize;
  231.     Fs_Stream     *filePtr;
  232.     int     fsInfoSize;
  233.     Vm_ExecInfo    *execInfoPtr;
  234.     Vm_ExecInfo    *oldExecInfoPtr;
  235.     Boolean    usedFile;
  236.  
  237.  
  238.     fsInfoSize = Fs_GetEncapSize();
  239.  
  240.     for (seg = VM_CODE; seg < VM_NUM_SEGMENTS; seg++) {
  241.     Byte_EmptyBuffer(buffer, int, offset);
  242.     Byte_EmptyBuffer(buffer, int, fileAddr);
  243.     Byte_EmptyBuffer(buffer, int, type);
  244.     if (type != seg) {
  245.         if (proc_MigDebugLevel > 0) {
  246.         panic("Vm_DeencapState: mismatch getting segment %d\n",
  247.               seg);
  248.         return(FAILURE);
  249.         }
  250.     }
  251.     Byte_EmptyBuffer(buffer, int, numPages);
  252.     Byte_EmptyBuffer(buffer, int, ptSize);
  253.     switch (type) {
  254.         case VM_CODE: {
  255.         varSize = sizeof(Vm_ExecInfo);
  256.         oldExecInfoPtr = (Vm_ExecInfo *) buffer;
  257.         buffer += varSize;
  258.         status = Fsio_DeencapStream(buffer, &filePtr);
  259.         buffer += fsInfoSize;
  260.         if (status != SUCCESS) {
  261.             printf("Vm_DeencapState: Fsio_DeencapStream returned status %x.\n",
  262.                status);
  263.             return(status);
  264.         }
  265.         if (filePtr->ioHandlePtr == (Fs_HandleHeader *) NIL) {
  266.             printf("Vm_DeencapState: stream has NIL ioHandlePtr\n");
  267.             return FAILURE;
  268.         }
  269.         segPtr = Vm_FindCode(filePtr, procPtr, &execInfoPtr, &usedFile);
  270.         if (segPtr == (Vm_Segment *) NIL) {
  271.             segPtr = Vm_SegmentNew(VM_CODE, filePtr, fileAddr,
  272.                        numPages, offset, procPtr);
  273.             if (segPtr == (Vm_Segment *) NIL) {
  274.             Vm_InitCode(filePtr, (Vm_Segment *) NIL,
  275.                     (Vm_ExecInfo *) NIL);
  276.             (void)Fs_Close(filePtr);
  277.             return(VM_NO_SEGMENTS);
  278.             }
  279.             Vm_ValidatePages(segPtr, offset, 
  280.                      offset + numPages - 1, FALSE, TRUE);
  281.             Vm_InitCode(filePtr, segPtr, oldExecInfoPtr);
  282.         } else {
  283.             if (!usedFile) {
  284.             (void)Fs_Close(filePtr);
  285.             }
  286.         }
  287.         procPtr->vmPtr->segPtrArray[type] = segPtr;
  288.         break;
  289.         }
  290.         case VM_HEAP: {
  291.         Fsio_StreamCopy(procPtr->vmPtr->segPtrArray[VM_CODE]->filePtr,
  292.                     &filePtr);
  293.         if (filePtr == (Fs_Stream *) NIL) {
  294.             panic("Vm_DeencapState: no code file pointer.\n");
  295.         }
  296.         break;
  297.         }
  298.         case VM_STACK: {
  299.         filePtr = (Fs_Stream *) NIL;
  300.         break;
  301.         }
  302.         default: {
  303.         panic("Vm_DeencapState: unknown segment type.\n");
  304.         }
  305.     }
  306.     if (type != VM_CODE) {
  307.         segPtr = Vm_SegmentNew(type, filePtr, fileAddr, numPages,
  308.                    offset, procPtr);
  309.         if (segPtr == (Vm_Segment *) NIL) {
  310.         return(VM_NO_SEGMENTS);
  311.         }
  312.         procPtr->vmPtr->segPtrArray[type] = segPtr;
  313.         segPtr->ptSize = ptSize;
  314.         varSize = ptSize * sizeof(Vm_PTE);
  315.         LoadSegment(varSize, buffer, segPtr);
  316.         buffer += varSize;
  317.         if (proc_MigDebugLevel > 4) {
  318.         printf("Deencapsulating swap file for segment %d.\n", type);
  319.         }
  320.         status = Fsio_DeencapStream(buffer, &segPtr->swapFilePtr);
  321.         buffer += fsInfoSize;
  322.         if (status != SUCCESS) {
  323.         printf("Vm_DeencapState: Fsio_DeencapStream on swapFile returned status %x.\n",
  324.                status);
  325.         return(status);
  326.         }
  327.         if (proc_MigDebugLevel > 4) {
  328.         printf("Deencapsulated swap file successfully.\n");
  329.         }
  330.         if (segPtr->swapFileName != (char *) NIL) { 
  331.         free(segPtr->swapFileName);
  332.         segPtr->swapFileName = (char *) NIL;
  333.         }
  334.         segPtr->flags |= VM_SWAP_FILE_OPENED;
  335.     }
  336.     }
  337.     return(SUCCESS);
  338. }
  339.  
  340.  
  341. /*
  342.  *----------------------------------------------------------------------
  343.  *
  344.  * Vm_FinishMigration --
  345.  *
  346.  *    Clean up the state of a process's virtual memory after migration.
  347.  *    The process control blocked is assumed to be unlocked on entry.
  348.  *
  349.  *        .. OBSOLETE ..
  350.  *
  351.  * Results:
  352.  *    SUCCESS.
  353.  *
  354.  * Side effects:
  355.  *    Deletes segments for the process.
  356.  *
  357.  *----------------------------------------------------------------------
  358.  */
  359. /* ARGSUSED */
  360. ReturnStatus
  361. Vm_FinishMigration(procPtr, hostID, infoPtr, bufferPtr, failure)
  362.     register Proc_ControlBlock     *procPtr;  /* The process being migrated */
  363.     int hostID;                   /* host to which it migrates */
  364.     Proc_EncapInfo *infoPtr;           /* area w/ information about
  365.                         * encapsulated state */
  366.     Address bufferPtr;               /* Pointer to allocated buffer */
  367.     int failure;               /* indicates whether migration
  368.                           succeeded */
  369. {
  370.     int seg;
  371.     
  372.     if (proc_MigDebugLevel > 4) {
  373.     printf("Vm_FinishMigration called.\n");
  374.     }
  375.     
  376.     for (seg = VM_CODE; seg < VM_NUM_SEGMENTS; seg++) {
  377.     if (proc_MigDebugLevel > 5) {
  378.         printf("Vm_FinishMigration deleting segment %d.\n", seg);
  379.     }
  380.     Vm_SegmentDelete(procPtr->vmPtr->segPtrArray[seg], procPtr);
  381.     }
  382.     /*
  383.      * Would also need to set PROC_NO_VM here...
  384.      */
  385.     return(SUCCESS);
  386. }
  387.  
  388.  
  389. /*
  390.  * ----------------------------------------------------------------------------
  391.  *
  392.  * EncapSegment --
  393.  *
  394.  *     Copy the information from a Vm_Segment into a buffer, ready to
  395.  *    be transferred to another node.  We have to duplicate the
  396.  *    stream to the swap or code file for the segment because
  397.  *    Fsio_EncapStream effectively closes the stream.  By dup'ing the
  398.  *    stream we can later call Vm_SegmentDelete which will close the
  399.  *    stream (again).
  400.  *
  401.  * Results:
  402.  *      If an error occurred writing the swap file, VM_SWAP_ERROR is
  403.  *    returned, else SUCCESS.  The new pointer into the buffer
  404.  *    is returned in *bufPtrPtr.
  405.  *
  406.  * Side effects:
  407.  *      None.
  408.  *
  409.  * ----------------------------------------------------------------------------
  410.  */
  411.  
  412. static ReturnStatus
  413. EncapSegment(segPtr, procPtr, bufPtrPtr)
  414.     Vm_Segment    *segPtr;    /* Pointer to the segment to be migrated */
  415.     Proc_ControlBlock     *procPtr;  /* The process being migrated */
  416.     Address    *bufPtrPtr;    /* pointer to pointer into buffer */
  417. {
  418.     register Address ptr;
  419.     int varSize;
  420.     ReturnStatus status;
  421.     Fs_Stream *dummyStreamPtr;
  422.  
  423.     if (segPtr->type != VM_CODE) {
  424.     varSize = segPtr->ptSize * sizeof(Vm_PTE);
  425.     } else {
  426.     varSize = sizeof(Vm_ExecInfo);
  427.     }
  428.  
  429.     ptr = *bufPtrPtr;
  430.     bcopy((Address) &segPtr->offset, ptr, NUM_FIELDS * sizeof(int));
  431.     ptr += NUM_FIELDS * sizeof(int);
  432.     if (segPtr->type != VM_CODE) {
  433.     bcopy((Address) segPtr->ptPtr, ptr, varSize);
  434.     ptr += varSize;
  435.     Fsio_StreamCopy(segPtr->swapFilePtr, &dummyStreamPtr);
  436.     status = Fsio_EncapStream(segPtr->swapFilePtr, ptr);
  437.     } else {
  438.     bcopy((Address) &segPtr->execInfo, ptr, varSize);
  439.     ptr += varSize;
  440.     Fsio_StreamCopy(segPtr->filePtr, &dummyStreamPtr);
  441.     status = Fsio_EncapStream(segPtr->filePtr, ptr);
  442.     }
  443.     if (status != SUCCESS) {
  444.     return(status);
  445.     }
  446.     *bufPtrPtr = ptr + Fs_GetEncapSize();
  447.  
  448.     if (proc_MigDebugLevel > 4) {
  449.     printf("Deleting segment %d from encapsulation routine.\n",
  450.            segPtr->type);
  451.     }
  452.     Proc_Unlock(procPtr);
  453.     VmMach_HandleSegMigration(segPtr);
  454.     Vm_SegmentDelete(segPtr, procPtr);
  455.     Proc_Lock(procPtr);
  456.     if (proc_MigDebugLevel > 4) {
  457.     printf("Deleted segment.\n");
  458.     }
  459.  
  460.     return(SUCCESS);
  461. }
  462.  
  463.  
  464.  
  465. /*
  466.  *----------------------------------------------------------------------
  467.  *
  468.  * LoadSegment --
  469.  *
  470.  *    Copy the page table for a segment from a buffer area into the
  471.  *     segment's page table.  
  472.  *
  473.  * Results:
  474.  *    None.
  475.  *
  476.  * Side effects:
  477.  *    The page table is loaded.
  478.  *
  479.  *----------------------------------------------------------------------
  480.  */
  481. ENTRY static void
  482. LoadSegment(length, buffer, segPtr)
  483.     int                length;
  484.     register    Address        buffer;
  485.     register    Vm_Segment    *segPtr;
  486. {
  487.     LOCK_MONITOR;
  488.  
  489.     bcopy(buffer, (Address) segPtr->ptPtr, length);
  490.  
  491.     UNLOCK_MONITOR;
  492. }
  493.  
  494.  
  495. /*
  496.  *----------------------------------------------------------------------
  497.  *
  498.  * CheckSharers --
  499.  *
  500.  *    Verify that a process is not using shared memory.  
  501.  *
  502.  * Results:
  503.  *    SUCCESS if not, or GEN_PERMISSION_DENIED if so.
  504.  *    Once we can handle shared memory processes, it will return
  505.  *    SUCCESS and rely on the special flag in the encapInfo structure
  506.  *    to fix things up.
  507.  *
  508.  * Side effects:
  509.  *    None.
  510.  *
  511.  *----------------------------------------------------------------------
  512.  */
  513. ENTRY static ReturnStatus
  514. CheckSharers(segPtr, infoPtr)
  515.     register    Vm_Segment    *segPtr;
  516.     Proc_EncapInfo *infoPtr;            /* area w/ information about
  517.                          * encapsulated state */
  518.     
  519. {
  520.     LOCK_MONITOR;
  521.  
  522.     if (segPtr->refCount > 1) {
  523.     infoPtr->special = 1;
  524.     if (proc_MigDebugLevel > 0) {
  525.         printf("Vm_InitiateMigration: can't migrate process sharing heap.\n");
  526.     }
  527.     UNLOCK_MONITOR;
  528.     return(FAILURE);
  529.     }
  530.     UNLOCK_MONITOR;
  531.     return(SUCCESS);
  532. }
  533.  
  534.  
  535. /*
  536.  * ----------------------------------------------------------------------------
  537.  *
  538.  * PrepareSegment --
  539.  *
  540.  *    Set up a segment to be migrated.  Lock its dirty pages and free
  541.  *    the rest.  
  542.  *
  543.  * Results:
  544.  *         The number of pages flushed is returned.
  545.  *
  546.  * Side effects:
  547.  *         All modified pages allocated to the segment are locked; other
  548.  *    pages are freed.
  549.  *
  550.  * ----------------------------------------------------------------------------
  551.  */
  552. ENTRY static void
  553. PrepareSegment(segPtr)
  554.     Vm_Segment    *segPtr;    /* Pointer to the segment to be flushed */
  555. {
  556.     Vm_PTE        *ptePtr;
  557.     Vm_VirtAddr        virtAddr;
  558.     Boolean        referenced;
  559.     Boolean        modified;
  560.     register int    i;
  561.  
  562.     LOCK_MONITOR;
  563.  
  564.     virtAddr.segPtr = segPtr;
  565.     virtAddr.sharedPtr = (Vm_SegProcList *) NIL;
  566.  
  567.     if (segPtr->type == VM_STACK) {
  568.     virtAddr.page = mach_LastUserStackPage - segPtr->numPages + 1;
  569.     ptePtr = VmGetPTEPtr(segPtr, virtAddr.page);
  570.     } else {
  571.     virtAddr.page = segPtr->offset;
  572.     ptePtr = segPtr->ptPtr;
  573.     }
  574.  
  575.     /*
  576.      * Free all clean pages that this segment has in real memory.
  577.      * Lock the dirty ones.
  578.      */
  579.  
  580.     for (i = 0; 
  581.      i < segPtr->numPages; 
  582.      i++, virtAddr.page++, VmIncPTEPtr(ptePtr, 1)) {
  583.     /*
  584.      * If the page is not resident in memory then go to the next page.
  585.      */
  586.     if (!(*ptePtr & VM_PHYS_RES_BIT)) {
  587.         continue;
  588.     }
  589.     /*
  590.      * The page is resident so lock it if it needs to be written, or else
  591.      * free the page frame.
  592.      */
  593.     VmMach_GetRefModBits(&virtAddr, Vm_GetPageFrame(*ptePtr), &referenced,
  594.                  &modified);
  595.     if ((*ptePtr & VM_MODIFIED_BIT) || modified) {
  596.         VmLockPageInt(Vm_GetPageFrame(*ptePtr));
  597.     } else {
  598.         VmPageFreeInt(Vm_GetPageFrame(*ptePtr));
  599.         *ptePtr &= ~(VM_PHYS_RES_BIT | VM_PAGE_FRAME_FIELD);
  600.         segPtr->resPages--;
  601.     }
  602.     }
  603.  
  604.     UNLOCK_MONITOR;
  605. }
  606.  
  607. /*
  608.  * ----------------------------------------------------------------------------
  609.  *
  610.  * FlushSegment --
  611.  *
  612.  *         Flush the dirty pages of a segment to disk.  This part is done
  613.  *    without the monitor lock because it calls monitored procedures.
  614.  *
  615.  * Results:
  616.  *         If the swap file cannot be opened, the error is propagated.  Otherwise,
  617.  *    SUCCESS is returned.
  618.  *
  619.  * Side effects:
  620.  *     All modified pages allocated to the segment are forced to disk.
  621.  *
  622.  * ----------------------------------------------------------------------------
  623.  */
  624. static ReturnStatus
  625. FlushSegment(segPtr)
  626.     Vm_Segment     *segPtr;    /* Pointer to the segment to be flushed */
  627. {
  628.     Vm_PTE        *ptePtr;
  629.     Vm_VirtAddr        virtAddr;
  630.     int            i;
  631.     ReturnStatus    status;
  632. #ifndef CLEAN
  633.     int            pagesWritten = 0;
  634. #endif /* CLEAN */
  635.  
  636.     /*
  637.      * Open the swap file unconditionally.
  638.      */
  639.     
  640.     VmSwapFileLock(segPtr);
  641.     if (!(segPtr->flags & VM_SWAP_FILE_OPENED)) {
  642.     status = VmOpenSwapFile(segPtr);
  643.     if (status != SUCCESS) {
  644.         VmSwapFileUnlock(segPtr);
  645.         return(status);
  646.     }
  647.     }
  648.     VmSwapFileUnlock(segPtr);
  649.  
  650.     virtAddr.segPtr = segPtr;
  651.     virtAddr.sharedPtr = (Vm_SegProcList *) NIL;
  652.  
  653.     if (segPtr->type == VM_STACK) {
  654.     virtAddr.page = mach_LastUserStackPage - segPtr->numPages + 1;
  655.     ptePtr = VmGetPTEPtr(segPtr, virtAddr.page);
  656.     } else {
  657.     virtAddr.page = segPtr->offset;
  658.     ptePtr = segPtr->ptPtr;
  659.     }
  660.  
  661.     /*
  662.      * Go through the page table and cause all modified pages to be
  663.      * written to disk.  During encapsulation time, we'll start at the
  664.      * top and free each page.  This has the side-effect of waiting
  665.      * for dirty pages to go to disk.  Note that by doing this
  666.      * two-pass write, multiple pages may be written to disk at once
  667.      * since the writes are asynchronous.
  668.      */
  669.     
  670.     for (i = 0; 
  671.      i < segPtr->numPages; 
  672.      i++, virtAddr.page++, VmIncPTEPtr(ptePtr, 1)) {
  673.     /*
  674.      * If the page is not resident in memory then go to the next page.
  675.      */
  676.     if (!(*ptePtr & VM_PHYS_RES_BIT)) {
  677.         continue;
  678.     }
  679.     /*
  680.      * The page is dirty so put it on the dirty list.  Wait later on
  681.      * for it to be written out.
  682.      */
  683. #ifndef CLEAN
  684.     pagesWritten++;
  685. #endif /* CLEAN */
  686.     
  687.     VmPutOnDirtyList(Vm_GetPageFrame(*ptePtr));
  688.     }
  689. #ifndef CLEAN
  690.     if (proc_MigDoStats) {
  691.         Proc_MigAddToCounter(pagesWritten,
  692.                  &proc_MigStats.varStats.pagesWritten,
  693.                  &proc_MigStats.squared.pagesWritten);
  694.     }
  695. #endif /* CLEAN */
  696.     return(SUCCESS);
  697. }
  698.  
  699.  
  700.  
  701. /*
  702.  *----------------------------------------------------------------------
  703.  *
  704.  * FreePages --
  705.  *
  706.  *    Free the pages of a segment (waiting for them to be written first).
  707.  *
  708.  * Results:
  709.  *    None.
  710.  *
  711.  * Side effects:
  712.  *    The pages are freed..
  713.  *
  714.  *----------------------------------------------------------------------
  715.  */
  716.  
  717. static void
  718. FreePages(segPtr)
  719.     Vm_Segment *segPtr;        /* segment whose pages should be freed */
  720. {
  721.     Vm_PTE        *ptePtr;
  722.     Vm_VirtAddr        virtAddr;
  723.     int            i;
  724.  
  725.     virtAddr.segPtr = segPtr;
  726.     virtAddr.sharedPtr = (Vm_SegProcList *) NIL;
  727.  
  728.     if (segPtr->type == VM_STACK) {
  729.     virtAddr.page = mach_LastUserStackPage - segPtr->numPages + 1;
  730.     ptePtr = VmGetPTEPtr(segPtr, virtAddr.page);
  731.     } else {
  732.     virtAddr.page = segPtr->offset;
  733.     ptePtr = segPtr->ptPtr;
  734.     }
  735.  
  736.     for (i = 0; 
  737.      i < segPtr->numPages; 
  738.      i++, virtAddr.page++, VmIncPTEPtr(ptePtr, 1)) {
  739.     /*
  740.      * If the page is not resident in memory then go to the next page.
  741.      */
  742.     if (!(*ptePtr & VM_PHYS_RES_BIT)) {
  743.         continue;
  744.     }
  745.     VmPageFree(Vm_GetPageFrame(*ptePtr));
  746.     segPtr->resPages--;
  747.     *ptePtr = VM_VIRT_RES_BIT | VM_ON_SWAP_BIT;
  748.     }
  749. }
  750.